﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dubs_Finder.Model
{
    internal class CheckEm : NotifyBase
    {
        private CyclicalFileBuffer fb;
        private ObservableCollection<DubsWrapper> dw;
        private MainModel mainModel;

 
        Dubs_Finder.Model.MainModel.updateScannedCounter usc;
        Dubs_Finder.Model.MainModel.updateStateText ust;

        internal CheckEm(CyclicalFileBuffer cb, ObservableCollection<DubsWrapper> dw, MainModel mainModel, Dubs_Finder.Model.MainModel.updateScannedCounter d, Dubs_Finder.Model.MainModel.updateStateText d1)
        {
            this.fb = cb;
            this.dw = dw;
            this.mainModel = mainModel;
            this.usc = d;
            this.ust = d1;
        }

        internal void runCheck(DirectoryInfo dir)
        {
            try
            {
                // Get subdirectories for a recursive search
                DirectoryInfo[] subDir = dir.GetDirectories();
                foreach (DirectoryInfo dInfo in subDir)
                {
                    runCheck(dInfo);
                }

                // Get the FileInfo objects for every file in the directory.
                FileInfo[] files = dir.GetFiles();
                // Compute and print the hash values for each file in directory. 
                FileWrapper fw, tmpFw;
                foreach (FileInfo fInfo in files)
                {
                    Debug.WriteLine(fInfo.FullName);
                    this.ust("Scanning: " + dir.Name + "/" + fInfo.Name);
                    Hasher h = new Hasher(fInfo, false);
                    h.ComputeHash();
                    fw = new FileWrapper(fInfo, h.HashString);
                    tmpFw = this.fb.ContainsSimilar(fw);
                    if (tmpFw == null) this.fb.addFile(fw);
                    else
                    {
                        this.fb.addFile(fw);
                        // Find any DubsWrappers with the same hash
                        IEnumerable<DubsWrapper> query = this.dw.Where(dubWrapper => String.Equals(dubWrapper.Hash, h.HashString));
                        //Make sure we found some
                        Debug.WriteLineIf(query == null, "query is null");
                        if (query != null)
                        {
                            bool added = false;
                            foreach (DubsWrapper dWrapper in query)
                            {
                                if (String.Equals(dWrapper.Hash, h.HashString) && dWrapper.FileSize == fInfo.Length)
                                {
                                    dWrapper.addLookALike(fw);
                                    added = true;
                                    Debug.WriteLine("Found existing dub");
                                    NotifyPropertyChanged("DubsWrapper");
                                    break;
                                }
                            }

                            if (added == false)
                            {
                                DubsWrapper tmp = new DubsWrapper(h.HashString, fInfo.Length, tmpFw);
                                tmp.addLookALike(fw);
                                dw.Add(tmp);
                                NotifyPropertyChanged("DubsWrapper");
                                Debug.WriteLine("First dub with this size");
                            }
                        }
                    }
                    //Debug.WriteLine(h.HashString + "\n");
                    usc(++this.mainModel.ScannedFiles);
                    NotifyPropertyChanged("ScannedFiles");
                }
                //Debug.WriteLine("Done");
                return;
            }
            catch (DirectoryNotFoundException)
            {
                Console.WriteLine("Error: The directory specified could not be found.");
            }
            catch (IOException)
            {
                Console.WriteLine("Error: A file in the directory could not be accessed.");
            }
            catch (UnauthorizedAccessException e)
            {
                Debug.WriteLine("Error: Access to a file or directory was denied");
                Debug.WriteLine(e.StackTrace);
            }
        }

    }
}
